using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;

public class Character : MonoBehaviour, ISaveAble {

    [Header("事件监听")]
    public VoidEventSO NewGameEvent;

    [Header("基本属性")]
    public float maxHealth;
    public float curHealth;
    public float maxPower;
    public float curPower;
    public float powerRecoverSpeed;
    public bool isBee;

    [Header("受伤无敌")]
    public float invincibleDuration;    // 受伤后的无敌时间
    public float invincibleCounter;    // 当前无敌计时
    public bool invincible;            // 当前是否处于无敌状态

    [Header("事件广播")]
    public UnityEvent<Character> OnHealthChange;  // 血条事件 
    public UnityEvent<Transform> OnTakeDamage;    // 受伤事件
    public UnityEvent OnDie;                      // 死亡事件

    private float cameraBottomY;                  // 摄像机下边界

    private void Start() {
        curHealth = maxHealth;

        // 获得摄像机底部的世界坐标Y值
        Camera mainCamera = Camera.main;
        if (mainCamera != null) {
            cameraBottomY = mainCamera.ViewportToWorldPoint(new Vector3(0, 0, 0)).y;
        }
    }

    private void OnEnable() {
        NewGameEvent.OnEventRaised += NewGame;

        // 注册数据
        ISaveAble saveable = this;
        saveable.RegisterSaveData();
    }
    private void OnDisable() {
        NewGameEvent.OnEventRaised -= NewGame;

        // 注销数据
        ISaveAble saveable = this;
        saveable.UnRegisterSaveData();
    }

    private void NewGame() {
        curHealth = maxHealth;
        curPower = maxPower;
        OnHealthChange?.Invoke(this);
    }

    private void Update() {
        if (invincible) {  // 如果当前处于无敌状态
            invincibleCounter -= Time.deltaTime;    // 减少无敌时间
            if (invincibleCounter <= 0) {    // 无敌时间结束
                invincible = false;
            }
        }

        // 能量条随着时间恢复
        if (curPower < maxPower) {
            curPower += Time.deltaTime * powerRecoverSpeed;
        }

        // 检查角色是否掉出摄像机下边界，Bee除外
        if (!isBee) {
            checkCamara();
        }
    }

    private void OnTriggerStay2D(Collider2D other) {
        if (other.CompareTag("Water")) {
            if (curHealth > 0) {
                curHealth = 0;
                // 触发死亡
                OnDie?.Invoke();
                // 血条改变
                OnHealthChange?.Invoke(this);
            }
        }
    }

    public void takeDamage(Attack attacker) {
        if (invincible) {   // 如果当前处于无敌状态，那么伤害计算不需要进行
            return;
        }

        if (curHealth - attacker.damage > 0) {
            curHealth -= attacker.damage;   // 扣血
            TriggerInvincible();            // 进入无敌帧
            // 执行受伤
            OnTakeDamage?.Invoke(attacker.transform);
        } else {
            curHealth = 0;
            // 触发死亡
            OnDie?.Invoke();
        }
        
        // 血条改变
        OnHealthChange?.Invoke(this);
    }

    private void TriggerInvincible() {  // 触发无敌帧
        if (!invincible) {
            invincible = true;
            invincibleCounter = invincibleDuration;
        }
    }

    public void OnSlide(float cost) {
        curPower -= cost;
        OnHealthChange?.Invoke(this);
    }

    private void checkCamara() {
        // 检查对象的位置是否低于摄像机底部
        if (transform.position.y < cameraBottomY) {
            // 死亡
            if (curHealth > 0) {
                curHealth = 0;
                // 触发死亡
                OnDie?.Invoke();
                // 血条改变
                OnHealthChange?.Invoke(this);
            }
        }
    }

    public DataDefination GetDataID() {
        return GetComponent<DataDefination>();
    }

    public void GetSaveData(Data data) {
        if (data.characterPosDict.ContainsKey(GetDataID().ID)) {
            data.characterPosDict[GetDataID().ID] = new SerializeVector3(transform.position);
            data.floatSavedData[GetDataID().ID + "health"] = this.curHealth;
            data.floatSavedData[GetDataID().ID + "power"] = this.curPower;
        } else {
            data.characterPosDict.Add(GetDataID().ID, new SerializeVector3(transform.position));
            data.floatSavedData.Add(GetDataID().ID + "health", this.curHealth);
            data.floatSavedData.Add(GetDataID().ID + "power", this.curPower);
        }
    }

    public void LoadData(Data data) {
        if (data.characterPosDict.ContainsKey(GetDataID().ID)) {
            transform.position = data.characterPosDict[GetDataID().ID].ToVector3();
            this.curHealth = data.floatSavedData[GetDataID().ID + "health"];
            this.curPower = data.floatSavedData[GetDataID().ID + "power"];
            
            // 通知UI更新
            OnHealthChange?.Invoke(this);
        }
    }
}